/**
 * GB28181服务监听程序
 */
const sip = require('sip');
const log4js = require('../../utils/logUtils');
const logger = log4js.getLogger('sip');
const dbHandler = require('../../service/dbhandler');

// 命令都放在这里
const registerHandler = require('./handler/registerHandler');
const serverMessageHandler = require('./handler/serverMessageHandler');
const clientMessageHandler = require('../client/handler/clientMessageHandler');
const serverInviteHandler = require('./handler/serverInviteHandler');
const clientInviteHandler = require('../client/handler/messages/clientInviteHandler');
const byeFactory = require('./factory/byeFactory');
const inviteFactory = require('./factory/inviteFactory');
const catalogFactory = require('./factory/catalogFactory');
const deviceinfoFactory = require('./factory/deviceinfoFactory');
const subscribeHandler = require("../client/handler/messages/subscribeHandler");
const ackHandler = require("../client/handler/messages/ackHandler");
const clientByeHandler = require("../client/handler/messages/clientByeHandler");
const recordFactory = require("./factory/recordFactory");
const config = require("../../db/config");
const deviceCache = require("../../db/deviceCache");
const settingModel = require("../../model/setting");

const TAG = "[SIP服务端]";
/**
 * SIP服务端
 */
const sipServer = {
    running: false,
    receiveCallIdMap: {},
    sendCallIdMap: {},
    stop: function () {
        if (this.running) {
            sip.stop();
        }
    },
    // 重启GB28181 服务
    restart: function () {
        if (!sipServer.running) {
            sipServer.start();
        }
    },
    /**
     * 启动 sip 服务端
     */
    start: function () {
        let that = sipServer;

        sip.start({ port: settingModel.cache.sip_command_port, udp: settingModel.cache.udp, tcp: settingModel.cache.tcp,
            logger: {
                send: function (message) {
                    let callId = message.headers['call-id'];
                    if (callId) {
                        callId = callId.replace(/"/g, '');
                        if(that.sendCallIdMap[callId]){
                            return;
                        }
                        that.sendCallIdMap[callId] = {time: new Date().getTime()};
                    }
                    // 对消息超过1分钟的call-id删除
                    for (let key in that.sendCallIdMap) {
                        if (that.sendCallIdMap.hasOwnProperty(key)) {
                            let obj = that.sendCallIdMap[key];
                            if (obj.time + 60 * 1000 < new Date().getTime()) {
                                delete that.sendCallIdMap[key];
                            }
                        }
                    }
                    // logger.info('[发送消息]', message);
                    // 重复的call-id的不显示日志
                    logger.info(TAG, '[发送消息] ',message,
                        'call-id='+message.headers['call-id'],
                        message.method ?'method=' + message.method:'',
                        message.content ?'content=' + message.content:'',
                        'via=', message.headers.via[0],
                        message.headers.via.length > 1 ? message.headers.via[1] : '');
                },
                recv: function (rq, address) {
                    // 取出 call-id ，如果是重复的消息，不处理
                    let callId = rq.headers['call-id'];
                    if (callId) {
                        if(that.receiveCallIdMap[callId]){
                            return;
                        }
                        callId = callId.replace(/"/g, '');
                        that.receiveCallIdMap[callId] = {time: new Date().getTime()};
                    }
                    // 对消息超过1分钟的call-id删除
                    for (let key in that.receiveCallIdMap) {
                        if (that.receiveCallIdMap.hasOwnProperty(key)) {
                            let obj = that.receiveCallIdMap[key];
                            if (obj.time + 60 * 1000 < new Date().getTime()) {
                                delete that.receiveCallIdMap[key];
                            }
                        }
                    }
                    // 不知道为什么有些消息在下面回调怎么取不到，临时放在这里处理
                    logger.info(TAG, '[接收消息] ',
                        'call-id=' + rq.headers['call-id'],
                        rq.reason ? 'reason=' + rq.reason : '',
                        rq.method ? 'method=' + rq.method : '',
                        rq.content ?'content=' + rq.content : '',
                        rq.status ? 'status=' + rq.status : '',
                        // 'address=', address,
                        // 'via=', rq.headers.via[0], rq.headers.via.length > 1 ? rq.headers.via[1] : ''
                    );
                    if (!rq.method) {
                        switch (rq.status) {
                            case 100:
                                // logger.info('[接收消息] retry');
                                break;
                            case 200:
                                if (rq.headers.cseq.method === 'INVITE') {
                                    serverInviteHandler.handle(rq);
                                }
                                break;
                            case 400:
                                logger.error('[接收消息] bad request', rq);
                                break;
                        }
                    }
                }
            }
        }, async function (rq) {
            // logger.info('[接收消息] ',rq);
            const receiveUri = sip.parseUri(rq.headers.from.uri);
            const deviceId = receiveUri.user;
            // 判断是上级还是下级，先看是不是下级
            const device =await deviceCache.cameras.find((item)=>{
                if(item.channel_id === deviceId){
                    return true;
                }
            });
            if(device){
                await that.dataClientHandler(rq, deviceId);
            }else{
                await that.dataServerHandler(rq, deviceId);
            }
            dbHandler.loadDevice(deviceId).then((obj)=>{
                if(obj) {

                }else{

                }
            }).catch((e)=>{
                logger.error(`[接收消息] 出现错误,deviceId=${deviceId}`, e);
            });

        });
    },
    // 消息分流处理,处理下级的消息
    dataServerHandler: async function (rq, deviceId) {
        if (!rq.method) {
            // method为空的放到logger的recv里处理了
            logger.info("这里到底能不能运行到");
        } else {
            // logger.info(`[接收消息] deviceId=${deviceId} method=${rq.method}`, rq.content);
            if (rq.method === 'REGISTER') {
                await registerHandler.handle(deviceId, rq);
            } else if (rq.method === 'MESSAGE') {
                await serverMessageHandler.handle(deviceId, rq);
            } else if (rq.method === 'ACK') {
                logger.info('[接收消息] TODO: Ack 消息未处理', rq);
            } else {
                logger.debug(`[接收消息] deviceId=${deviceId} TODO:尚不支持的方法:`, rq.method);
                sip.send(sip.makeResponse(rq, 405, 'Method Not Allowed'));
            }
        }
    },
    // 消息分流处理,这里的消息是向上级连时处理上级的消息
    dataClientHandler: async function (rq, deviceId) {
        if (!rq.method) {
            // method为空的放到logger的recv里处理了
        } else {
            logger.info(TAG, `[接收消息] deviceId=${deviceId} method=${rq.method}`);
            if (rq.method === 'REGISTER') {
                await registerHandler.handle(deviceId, rq);
            } else if (rq.method === 'ACK') {
                await ackHandler.handle(rq);
            } else if (rq.method === 'BYE') {
                await clientByeHandler.handle(rq);
            } else if (rq.method === 'MESSAGE') {
                await clientMessageHandler.handle(rq);
            } else  if (rq.method === 'SUBSCRIBE') {
                await subscribeHandler.handle(rq);
            } else if (rq.method === 'INVITE') {
                await clientInviteHandler.handle(rq);
            } else {
                logger.debug(TAG, `[接收消息] deviceId=${deviceId} TODO:尚不支持的方法:`, rq.method);
                sip.send(sip.makeResponse(rq, 405, 'Method Not Allowed'));
            }
        }
    },
    /**
     * 发invite消息，对外接口
     * @param media_ip
     * @param deviceId
     * @param channel
     * @param udpPort
     * @param startTime 回放开始时间
     * @param endTime 回放结束时间
     * @param s Play 或 Playback
     */
    invite:async  function (media_ip, deviceId, channel, udpPort, s='Play', startTime=0, endTime=0) {
        logger.info(TAG, "准备发invite消息", media_ip, deviceId, channel, udpPort);
        try {
            const obj = await dbHandler.loadDevice(deviceId);
            if (obj) {
                let cmd = await inviteFactory.invite(media_ip, deviceId, channel, udpPort, s, startTime, endTime);
                if (cmd) {
                    sip.send(cmd);
                }
                return true;
            } else {
                logger.error(TAG, `[发送消息] deviceId=${deviceId} TODO:404 设备不存在`);
                return false;
            }
        } catch (e) {
            logger.error(`[发送消息] deviceId=${deviceId} 发invite指令异常`, e);
            return false;
        }
    },
    /**
     * 对外的接口
     * @param deviceId
     * @param channel
     * @returns {Promise<void>}
     */
    bye: function (deviceId, channel) {
        const cmd = byeFactory.generate(deviceId, channel);
        this.sendCmd(cmd);
    },
    /**
     * 获取录像列表
     */
    recordList: async function (deviceId, channelId, startTime, endTime) {
        let SN = Math.round((new Date()).getTime() / 1000);
        const cmd = await recordFactory.generate(deviceId, channelId, startTime, endTime, SN);
        this.sendCmd(cmd);
        return SN;
    },
    /**
     * 请求设备列表
     * @param {*} deviceId
     */
    catalog: async function (deviceId) {
        const deviceInfo = await dbHandler.loadDevice(deviceId);
        const cmd = await catalogFactory.generate(deviceInfo);
        this.sendCmd(cmd);
    },
    deviceInfo: async function (deviceId) {
        const deviceInfo = await dbHandler.loadDevice(deviceId);
        const cmd = deviceinfoFactory.generate(deviceInfo);
        this.sendCmd(cmd);
    },
    sendCmd: function (cmd) {
        try {
            if (cmd) {
                logger.info('[发送消息] 内容:', cmd);
                sip.send(cmd);
            }
        } catch (e) {
            logger.error("[发送消息] 请求设备指令异常", cmd, e);
        }
    }
}

module.exports = sipServer;
